package club.emergency.wechat.staff.search.provider.impl;

import club.emergency.wechat.common.response.ResponseEntity;
import club.emergency.wechat.common.response.StatusCode;
import club.emergency.wechat.exeception.provider.ProviderException;
import club.emergency.wechat.model.staff.Staff;
import club.emergency.wechat.persistence.staff.StaffMapper;
import club.emergency.wechat.redis.RedisOperation;
import club.emergency.wechat.redis.common.RedisKeyConstant;
import club.emergency.wechat.sso.jwt.JwtTokenUtil;
import club.emergency.wechat.staff.search.StaffSearch;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * Create with IntelliJ IDEA
 * Project Name: wechat
 * Package Name: club.emergency.wechat.staff.search.provider.impl
 * Date: 2018/11/16
 *
 * @author: 快乐的小菌菌
 * Description:
 */
@Slf4j
@RestController
public class StaffSearchImpl implements StaffSearch {

    private StaffMapper staffMapper;

    private RedisOperation<Staff> redisOperation;

    @Value("${jwt.secretKey}")
    private String secretKey;

    @Value("${jwt.accessTokenExpired}")
    private long accessTokenExpired;

    @Value("${jwt.refreshTokenExpired}")
    private long refreshTokenExpired;

    public StaffSearchImpl(StaffMapper staffMapper, RedisOperation<Staff> redisOperation) {
        this.staffMapper = staffMapper;
        this.redisOperation = redisOperation;
    }

    @Override
    public String flipList(@RequestParam("pageNo") Integer pageNo, @RequestParam("pageSize") Integer pageSize) {
        Page<Staff> page = new Page<>(pageNo, pageSize);
        IPage<Staff> staffIPage = staffMapper.selectPage(page, null);
        return ResponseEntity.ok(StatusCode.DB_SEARCH_OK, "数据查询成功", staffIPage);
    }

    @Override
    public String signature(@RequestParam("openId") String openId) {
        Staff staff;
        try {
            staff = getStaffByOpenId(openId);
        } catch (ProviderException e) {
            return ResponseEntity.ok(StatusCode.LOGIN_ERROR, e.getMessage());
        }
        TokenModel tokenModel = createToken(staff.getId());
        tokenModel.setStaff(staff);
        //在每次登录的时候需要把staff对象传到内部对象中。注意：并不是放在jwt token中，仅仅是以变量形式传参，方便前台解析
        return ResponseEntity.ok(StatusCode.LOGIN_OK, "获取签名成功！", tokenModel);
    }

    @Override
    public String updateToken() {
        return ResponseEntity.ok(StatusCode.AUTHORIZATION_UPDATE_OK, "Token更新成功！", createToken(null));
    }

    @Override
    public String getById(@RequestParam("id") Long id) {
        Staff staff = staffMapper.selectById(id);
        if (Objects.isNull(staff)) {
            return ResponseEntity.error(StatusCode.DB_SEARCH_ERROR, "没有id为:" + id + "的人员信息");
        }
        return ResponseEntity.ok(StatusCode.DB_SEARCH_OK, "根据id查询人员成功!", staff);
    }

    @Override
    public String checkEachTest(@RequestParam("id") Long id) {
        Staff staff = staffMapper.selectById(id);
        if (staff.getEachTest().equals(1)) {
            return ResponseEntity.error(StatusCode.DB_SEARCH_ERROR, "今天的每日答题已经全部回答完毕！");
        }
        return ResponseEntity.ok(StatusCode.DB_SEARCH_OK, "今天的每日答题未全部回答！");
    }

    /**
     * 根据OpenId获取Staff对象
     *
     * @param openId 微信openid
     * @return 以字符串形式返回
     */
    private Staff getStaffByOpenId(String openId) {
        Boolean flag = redisOperation.hasKey(openId);
        Staff staff;
        if (flag) {
            staff = redisOperation.get(RedisKeyConstant.STAFF_OPENID + openId, Staff.class);
        } else {
            QueryWrapper<Staff> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("open_id", openId);
            Staff staffForQuery = staffMapper.selectOne(queryWrapper);
            //如果staff为null，证明该用户还未注册。
            if (Objects.isNull(staffForQuery)) {
                throw new ProviderException("没有OpenId对应的用户，请用户先注册绑定之后再进行操作!");
            } else {
                staff = staffForQuery;
                redisOperation.add(RedisKeyConstant.STAFF_OPENID + openId, staff, 3, TimeUnit.HOURS);
            }
        }
        return staff;
    }

    private TokenModel createToken(Long id) {
        String accessToken = JwtTokenUtil.createJWT(secretKey, String.valueOf(id), "accessToken", accessTokenExpired);
        String refreshToken = JwtTokenUtil.createJWT(secretKey, String.valueOf(id), "refreshToken", refreshTokenExpired);
        return new TokenModel(accessToken, refreshToken, null);
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    private class TokenModel {
        private String accessToken;
        private String refreshToken;
        private Staff staff;
    }
}
